#include "pch.h"
#include "geMatrix3d.h"

#define PTR glm::dmat4*
#define CPTR const glm::dmat4*


namespace jm
{

const geMatrix3d geMatrix3d::kIdintify = {
1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1
};

geMatrix3d::geMatrix3d()
{
	m_pxform = new glm::dmat4(1.0);
}

geMatrix3d::geMatrix3d(const geMatrix3d& src)
{
	*this = src;
}

geMatrix3d::geMatrix3d(double x0, double y0, double z0, double w0,
	double x1, double y1, double z1, double w1,
	double x2, double y2, double z2, double w2,
	double x3, double y3, double z3, double w3)
	: m_pxform(new glm::mat4(x0, y0, z0, w0,
		x1, y1, z1, w1,
		x2, y2, z2, w2,
		x3, y3, z3, w3))
{
}

geMatrix3d::~geMatrix3d()
{
	SAFE_DELETE(m_pxform);
}

geMatrix3d& geMatrix3d::operator=(const geMatrix3d& src)
{
	if (&src==this)
	{
		return *this;
	}

	*(PTR)m_pxform = *(PTR)src.m_pxform;
	return *this;
}

geMatrix3d& geMatrix3d::scaleBy(const geVector3d& vec)
{
	*(PTR)m_pxform = glm::scale(*(CPTR)m_pxform, glm::dvec3(vec.x, vec.y, vec.z));
	return *this;
}

geMatrix3d& geMatrix3d::scaleBy(double scale)
{
	return scaleBy(geVector3d(scale, scale, scale));
}

geMatrix3d& geMatrix3d::translateBy(const geVector3d& vec)
{
	*(PTR)m_pxform = glm::translate(*(CPTR)m_pxform, glm::dvec3(vec.x, vec.y, vec.z));
	return *this;
}

geMatrix3d& geMatrix3d::rotateBy(double angle, const geVector3d& axis)
{
	*(PTR)m_pxform = glm::rotate(*(CPTR)m_pxform, (glm::f64)angle, glm::dvec3(axis.x, axis.y, axis.z));
	return *this;
}

geMatrix3d& geMatrix3d::transposeBy()
{
	*(PTR)m_pxform = glm::transpose(*(CPTR)m_pxform);
	return *this;
}

geMatrix3d& geMatrix3d::inverse()
{
	*(PTR)m_pxform = glm::inverse(*(CPTR)m_pxform);
	return *this;
}

geMatrix3d geMatrix3d::loakAt(const geVector3d& eye, const geVector3d& center, const geVector3d& up)
{
	geMatrix3d tmp;
	*(PTR)tmp.m_pxform = glm::lookAt(glm::dvec3(eye.x, eye.y, eye.z),
		glm::dvec3(center.x, center.y, center.z),
		glm::dvec3(up.x, up.y, up.z));

	return tmp;
}

geMatrix3d geMatrix3d::ortho(double left, double right, double bottom, double top)
{
	geMatrix3d tmp;
	*(PTR)tmp.m_pxform = glm::ortho(left, right, bottom, top);

	return tmp;
}

geMatrix3d geMatrix3d::perspective(double fieldOfView, double aspect, double _near, double _far)
{
	geMatrix3d tmp;
	*(PTR)tmp.m_pxform = glm::perspective(fieldOfView, aspect, _near, _far);

	return tmp;
}

geMatrix3d geMatrix3d::scale(const geVector3d& vec)
{
	geMatrix3d tmp;
	tmp.scaleBy(vec);
	return tmp;
}

geMatrix3d geMatrix3d::scale(double scale)
{
	return geMatrix3d::scale(geVector3d(scale, scale, scale));
}

geMatrix3d geMatrix3d::translate(const geVector3d& vec)
{
	geMatrix3d tmp;
	tmp.translateBy(vec);
	return tmp;
}

geMatrix3d geMatrix3d::rotate(double angle, const geVector3d& axis)
{
	geMatrix3d tmp;
	tmp.rotateBy(angle, axis);
	return tmp;
}

geVector3d geMatrix3d::preMult(const geMatrix3d& xform, const geVector3d& vec)
{
	glm::dvec4 tvec(vec.x, vec.y, vec.z, 1.0);
	const glm::dmat4& tform = *(CPTR)xform.m_pxform;

	auto a = tform * tvec;
	return geVector3d(a.x, a.y, a.z);
}

gePoint3d geMatrix3d::preMult(const geMatrix3d& xform, const gePoint3d& vec)
{
	geVector3d dir = preMult(xform, geVector3d(vec.x, vec.y, vec.z));
	return gePoint3d(dir.x, dir.y, dir.z);
}

geVector3d geMatrix3d::postMult(const geMatrix3d& xform, const geVector3d& vec)
{
	glm::dvec4 tvec(vec.x, vec.y, vec.z, 1.0);
	const glm::dmat4& tform = *(CPTR)xform.m_pxform;

	auto a = tvec * tform;
	return geVector3d(a.x, a.y, a.z);
}

gePoint3d geMatrix3d::postMult(const geMatrix3d& xform, const gePoint3d& vec)
{
	geVector3d dir = postMult(xform, geVector3d(vec.x, vec.y, vec.z));
	return gePoint3d(dir.x, dir.y, dir.z);
}

geMatrix3d geMatrix3d::multiply(const geMatrix3d& xform1, const geMatrix3d& xform2)
{
	const glm::dmat4& tform1 = *(CPTR)xform1.m_pxform;
	const glm::dmat4& tform2 = *(CPTR)xform2.m_pxform;
	glm::dmat4 tform3 = glm::matrixCompMult(tform1, tform2);

	geMatrix3d tmp;
	*(PTR)tmp.m_pxform = tform3;
	return tmp;
}

geMatrix3d geMatrix3d::Multiply(const geMatrix3d& xform1, double scalar)
{
	const glm::dmat4& tform1 = *(CPTR)xform1.m_pxform;
	glm::dmat4 tmpmat = tform1 * scalar;
	geMatrix3d tmp;
	*(PTR)tmp.m_pxform = tmpmat;
	return tmp;
}


}